package the.broccoli.generator.engine;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.wisteria.framework.util.DateUtils;
import org.wisteria.framework.util.TextUtils;
import the.broccoli.generator.engine.po.WistData;
import the.broccoli.generator.engine.po.WistTpl;
import the.broccoli.generator.engine.template.FreemarkTemplate;

import java.io.File;
import java.util.*;
import java.util.regex.Matcher;

public class WistEngine {

    private static final String JAVA_PATH = "\\src\\main\\java\\";
    private static final String RESOURCES_PATH = "\\src\\main\\resources\\";

    private WistData data;
    private Set<String> tpls;

    private WistEngine() {}

    public WistEngine(WistData data, List<String> tpls) {
        doData(data);
        // 去重
        if (!CollectionUtils.isEmpty(tpls)) {
            this.tpls = new HashSet<>();
            for (String tpl : tpls) {
                this.tpls.add(tpl);
            }
        }
    }

    public void doGeneration() {
        if (CollectionUtils.isEmpty(this.tpls)) {
            return;
        }

        for (String tpl : this.tpls) {
            tpl = tpl.toUpperCase();
            if (WistTpl.MP.toString().toUpperCase().equals(tpl)) {
                doMpGeneration();
            } else if (WistTpl.CONTROLLER.toString().toUpperCase().equals(tpl)) {
                String packagePrefix = data.getWebPackagePrefix() + "." + data.getModuleName() + ".controller";
                String filePath = data.getWebProjectPath() + JAVA_PATH + packagePrefix.replaceAll("\\.", Matcher.quoteReplacement(File.separator)) + "\\" + getControllerName(data.getEntityClass());
                FreemarkTemplate.generate("controller.java.ftl", filePath, data);
            } else if (WistTpl.JS.toString().toUpperCase().equals(tpl)) {

            } else if (WistTpl.ADD.toString().toUpperCase().equals(tpl)) {

            } else if (WistTpl.EDIT.toString().toUpperCase().equals(tpl)) {

            } else if (WistTpl.LIST.toString().toUpperCase().equals(tpl)) {

            } else if (WistTpl.DETAIL.toString().toUpperCase().equals(tpl)) {

            }
        }
    }

    private String getControllerName(String bizNameEN) {
        return bizNameEN + "Controller.java";
    }


    public void doMpGeneration() {
        /**
         * 全局配置
         */
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setOutputDir(data.getProjectPath() + File.separator + "src" + File.separator + "main" + File.separator + "java");
        globalConfig.setOpen(false);
        globalConfig.setAuthor(data.getAuthor());
        globalConfig.setBaseResultMap(true);
        globalConfig.setBaseColumnList(true);

        /**
         * 数据库配置
         */
        DataSourceConfig dataSourceConfig = new DataSourceConfig();
        dataSourceConfig.setUrl(data.getUrl());
        dataSourceConfig.setDriverName("com.mysql.jdbc.Driver");
        dataSourceConfig.setUsername(data.getUserName());
        dataSourceConfig.setPassword(data.getPassword());

        // 包配置
        PackageConfig packageConfig = new PackageConfig();
        String projectPackage = data.getPackagePrefix();
        String moduleName = data.getModuleName();
        packageConfig.setParent(projectPackage);
        packageConfig.setModuleName(moduleName);
        //controller没用掉,生成之后会自动删掉
        packageConfig.setController("TTT");

        // 策略配置
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
        strategyConfig.setEntityTableFieldAnnotationEnable(true);
        // 父类
        strategyConfig.setSuperEntityClass("org.wisteria.framework.web.mvc.entity.SuperEntity");
        strategyConfig.setSuperMapperClass("org.wisteria.framework.web.mvc.dao.SuperMapper");
        strategyConfig.setSuperServiceClass("org.wisteria.framework.web.mvc.service.ISuperService");
        strategyConfig.setSuperServiceImplClass("org.wisteria.framework.web.mvc.service.AbstractSuperService");

        // 写于父类中的公共字段
        strategyConfig.setSuperEntityColumns("is_deleted", "created_time", "created_id", "created_name", "modified_time", "modified_id", "modified_name");
        // 表名，多个英文逗号分割
        strategyConfig.setInclude(data.getTableName());
        strategyConfig.setTablePrefix(moduleName + "_");

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null);

        // 自定义配置
        InjectionConfig injectionConfig = null;
        injectionConfig = new InjectionConfig() {
            @Override
            public void initMap() {
            }
        };
        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";
        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 ， 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化！！
                return data.getProjectPath() + RESOURCES_PATH + "mapper\\" + moduleName + "\\" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        injectionConfig.setFileOutConfigList(focList);

        AutoGenerator autoGenerator = new AutoGenerator();
        autoGenerator.setGlobalConfig(globalConfig);
        autoGenerator.setDataSource(dataSourceConfig);
        autoGenerator.setStrategy(strategyConfig);
        autoGenerator.setPackageInfo(packageConfig);
        autoGenerator.setTemplate(templateConfig);
        autoGenerator.setCfg(injectionConfig);
        autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
        autoGenerator.execute();

        destory(globalConfig.getOutputDir(), packageConfig.getParent());
    }

    /**
     * 删除不必要的代码
     */
    private void destory(String outputDir, String packageName) {
        String filePath = outputDir + "\\" + packageName.replaceAll("\\.", Matcher.quoteReplacement(File.separator)) + "\\TTT";
        deleteDir(new File(filePath));
    }

    /**
     * 删除目录
     *
     * @author guiyj007
     * @Date 2017/10/30 下午4:15
     */
    private boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        return dir.delete();
    }

    private void doData(WistData data) {
        data.setDate(DateUtils.formatTime(new Date()));

        String tableName = data.getTableName();
        String entityName = tableName;
        if (StringUtils.hasText(tableName)) {
            String tName = tableName = tableName.toLowerCase();
            String regex = data.getTableNameRegex();
            if (StringUtils.hasText(regex) && tableName.contains(regex)) {
                String moduleName = data.getModuleName().toLowerCase();

                tName = tName.substring((moduleName + regex).length());

                String[] array = tName.split(regex);
                if (array.length > 0) {
                    entityName = "";
                    for (int i = 0; i < array.length; i++) {
                        String str = array[i];
                        if (i > 0) {
                            str = TextUtils.firstCharToUpperCase(str);
                        }
                        entityName += str;
                    }
                }
            }
            data.setEntityName(entityName);
            data.setEntityClass(TextUtils.firstCharToUpperCase(entityName));
        }

        this.data = data;
    }
}
